package user

import (
	"reflect"
	codecs "sanguo/codec/cs"
	"sanguo/node/common/fusing"
	"sanguo/node/common/transaction"
	"sanguo/node/node_game"
	cs_message "sanguo/protocol/cs/message"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/sniperHW/kendynet"
)

type TransCreateFunc func(user *User, msg *codecs.Message) transaction.Transaction

var transFactory map[string]TransCreateFunc

func RegisterTransFunc(msg proto.Message, creator TransCreateFunc) {
	msgName := reflect.TypeOf(msg).String()
	if nil == creator {
		return
	}
	_, ok := transFactory[msgName]
	if ok {
		return
	}

	transFactory[msgName] = creator
}

func onUserMsg(session kendynet.StreamSession, msg *codecs.Message) {
	//node_game.Infoln("OnUserMsg:", msg)
	if session.GetUserData() == nil {
		node_game.Debugln("onUserMsg session.GetUserData() == nil", msg)
		return
	}
	u := session.GetUserData().(*User)
	if !u.checkStatus(status_playing) {
		node_game.Debugln("onUserMsg u.checkStatus(status_playing) == fasle", msg)
		return
	}
	_, ok := userMap[u.userID]
	if ok {
		name := msg.GetName()
		isFusing := false
		creator := transFactory[name]
		if creator != nil {
			trans := creator(u, msg)
			if fusing.IsMessageFusing(name) {
				isFusing = true
			} else if fusing.IsModuleFusing(trans.GetModuleName()) {
				isFusing = true
			} else {
				u.transMgr.PushTrans(trans, time.Second*transaction.TransTimeoutSec)
			}

			if isFusing {
				//如果消息或消息所属模块被熔断，直接响应错误
				resp := trans.GetReplyMsg()
				if nil != resp {
					mutable := reflect.ValueOf(resp).Elem()
					v := mutable.FieldByName("Errcode")
					if v.IsValid() {
						errcode := cs_message.EnumType(cs_message.EnumType_ERROR).Enum()
						v.Set(reflect.ValueOf(errcode))
						u.Reply(msg.GetSeriNo(), resp)
					}
				}
			}
		}
	}
}

func (this *User) EndTrans(trans transaction.Transaction) {
	this.transMgr.End(trans)
}

func (this *User) CheckTrans(trans transaction.Transaction) bool {
	return this.transMgr.CheckTrans(trans)
}
